<?php

if(!defined('OI')) {
			
	print '<h1>Access Error</h1>Sorry, this file can not be accessed directly, this is strictly forbidden!';
	exit();
				
}

class DigitalUniversity {

	# Javascript scripts
	public $onLoadScripts = array();

	# Define variables
	public $error = array();	
	public $isIE = false;
		
	# Configuration & language
	public $lang = array();	
	public $config = array();
		
	# User details
	public $user = array();
	
	# Declare inputs
	public $input = array();
	public $post = array();
		
	# Menu tree
	private $tree = array();	
	
	# Administrator level
	private $isAdmin = false;	
	
	# Security key
	private $cipherKey = '';
	private $cipherKeys = array('ji]3#3f?~!_"47a56n@~3aB}${aBD]9', 'l2k3j39alt0492~!<?$%£~$%"|£$%');
	
	/*
	 * Constructor: Store config details
	 * 	- PHP5 now uses pass by reference so we do not need to store the reference
	*/
	public function __construct(&$config) {
		
		$this->config =& $config;
				
	}
	
	public function javascriptLoader($script) {
	
		$this->onLoadScripts[] = $script;
		
	}
	
	public function getJavascriptLoad() {
	
		return $this->onLoadScripts;	
		
	}
	
	public function addPageTree($title, $link) {
	
		$this->tree[] = array('title' => $title, 'link' => $link);
		
	}
	
	public function getPageTree() {
	
		return $this->tree;	
		
	}
	
	/*
	 * clearSession: Remove the user session
	*/	
	public function clearSession() {
	
		setcookie('DigitialUniversity-User', NULL, time()-(60*60*24*365), '/');				
		return true;
		
	}
	
	/*
	 * Initialise: Main function to create all the system parts required:
	 * 	- Load database
	 *		- Clean inputs/variables
	 *		- Process extensions, user and language
	*/
	public function initialise($isAdmin = false) {
			
		# Store admin level
		$this->isAdmin = $isAdmin;
				
		# Load database
		$this->database();
		
		# Parse variables
		$this->parseVariables();
						
		# Get user class
		include_once(SOURCE_PATH.'class/User.php');
						
		# Create user instance
		$userClass = new User($this);
		$this->user = $userClass->getUserDetails();
		unset($userClass);
											
		# Generic template
		include_once(SOURCE_PATH.'class/GenericClass.php');	
					
	}
		
	/*
	 * Database: Load the database class and connection
	*/
	private function database(){
				
		include_once(SOURCE_PATH.'class/Database.php');
		$this->db = new Database($this->config);
											
	}
								
	/*
	 * addMenu: Template navigation, add parent menu
	*/
	public function addMenu($link, $title, $name, $subLink = '', $align = 'right') {
		
		$this->menu[] = array('link' => $link, 'title' => $title, 'subLink' => $subLink, 'name' => $name, 'align' => $align);
	
	}
	
	/*
	 * addSMenu: Add child to a given parent menu
	*/
	public function addSMenu($parent, $page, $name) {
	
		$this->submenu[$parent][] = array('parent' => $parent, 'page' => $page, 'name' => $name);
							
	}
		
	/*
	 * sortParse: Used by the template system to display each page, converting 
	 * template keys into processed data {lang-title}, etc..
	 *
	 * @param $contents - The text content to process
	 * @param $parse - An array of additional parse
	*/	
	public function sortParse($contents) {
		
		if(!empty($this->user)) {
			$contents = preg_replace('/{user-([^#"]+?)\}/e', '$this->user[\'$1\']', $contents);	
		}
						
		$contents = preg_replace('/{config-([^#"]+?)\}/e', '$this->config[\'$1\']', $contents);	
				
		return $contents;	
			
	}	
	
	/*
	 * Display: Include a file and output the processed content
	 *
	 * @param $fileName - The file to open and return
	 * @param $parse - The data to parse
	*/
	public function outputDesign($fileName, $arguments = array()) {
		
		# Define variables
		$isSafeToInclude = false;
				
		# Front or back?
		if($this->isAdmin) {
			if(preg_match('#\[module\]#', $fileName)) {
				$fileName = str_replace('[module]', '', $fileName);
				$file = ADMIN_PATH.'modules/'.$fileName.'.php';				
				if(file_exists($file)) {
					$isSafeToInclude = true;
					$fileName = ucfirst($this->input['endKey']).'Module';
				} else {
					$fileName = ucfirst($this->input['frontKey']).'Module';
					$file = ADMIN_PATH.'modules/'.$this->input['frontKey'].'.php';
				}
			} else {
				$file = ADMIN_PATH.'template/design/'.$fileName.'.php';
			}
		} else {
			$file = ROOT_PATH.'template/design/'.$fileName.'.php';
		}
										
		# Does the file exist?
		if(!$isSafeToInclude && file_exists($file)) {
			$isSafeToInclude = true;
		}
								
		if($isSafeToInclude) {
			
			# Define variable
			$display = '';
			
			# Include file
			include_once($file);
			
			# Check for class
			if(class_exists($fileName)) {
				
				# Start buffer
				ob_start();		
					$designClass = new $fileName($this, $arguments);																																																
					$display = $this->sortParse(ob_get_contents());	
					unset($designClass);																	
				ob_end_clean();	
			
			}
			
			# Clean memory
			unset($fileName, $file, $arguments);
						
			# Return buffer													
			return $display;
			
		} else {
		
			return NULL;
		
		}
		
	}
									
	/*
	 * getMicroTime: Calculate page loading time
	*/			 
	public function getMicroTime() {

		list($usec, $sec) = explode(" ", microtime());			
		return ((float) $usec + (float) $sec);
	
	}
							
	/*
	 * Escape: MySQL escape to stop SQL injections
	*/	
	private function escape($str) {
					
		return mysql_escape_string(stripslashes($str));
			
	}
	
	/*
	 * parseVariables: Parse the GET and POST variables
	 * overriding the original values 
	*/
	public function parseVariables(){
					    										
		$this->input = $this->parseVarLoop($_GET, array());		
		$this->post = $this->parseVarLoop($_POST, array());
												
	}
	
	/*
	 * parseVarLoop: Loop through each key and process the result
	*/	
	private function parseVarLoop(&$data){
			
		# Define variables
		$input = array();
				
		if(!empty($data)) {
		
			foreach($data as $k => $v) {
			
				if(is_array($v)) {
				
					$input[$k] = $this->parseVarLoop($data[$k]);
					
				} else {	
				
					$k = $this->parseKey($k);
					$v = $this->parseValue($v);
					
					$input[$k] = $v;
					
				}
				
			}
			
		}
		
		return $input;
		
	}
		
	private function parseKey($key){
	
    	if($key == '') {		
    		return '';			
    	}
    	
    	$key = htmlspecialchars(urldecode($key));		
    	$key = str_replace("&#032;", ' ', $this->escape($key)); 
    	
    	return $key;
		
    }
		
	private function parseValue($value){
	
    	if($value == '') {		
    		return '';			
    	}
    
		$value = nl2br($value);
    	$value = str_replace("&#032;", ' ', $this->escape($value));
		
		# PHP 5.4.0 - ENT_HTML5 
		$value = htmlentities($value, ENT_QUOTES, 'UTF-8');
				  		    	
    	return $value;
		
    }
		
	/*
	 * Dehtmlizer: Convert HTML entities into HTML parts
	*/	
	public function dehtmlizer($string){	
		$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);		
		$string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);		
		$trans_tbl = get_html_translation_table(HTML_ENTITIES);		
		$trans_tbl = array_flip($trans_tbl);		
		return strtr($string, $trans_tbl);		
	}
	
	/*
	 * timeSince: Calculate the time that has passed since a given integer timestamp.
	 * This returns the string outputted version of the time in:
	 * x seconds ago, x minutes ago, x days ago, etc
	 *
	 * If the timestamp is older than a month, it outputs a full text timestamp
	 *
	 * @param $original - The input timestamp
	 * @return - Formatted time string
	*/
	public function timeSince($original) {
		
		$chunks = array(
			array(60 * 60 * 24 * 365 , 'year'),
			array(60 * 60 * 24 * 30 , 'month'),
			array(60 * 60 * 24 * 7, 'week'),
			array(60 * 60 * 24 , 'day'),
			array(60 * 60 , 'hour'),
			array(60 , 'minute'),
			array(1, 'second')
		);
		
		$today = time();
		$since = $today - $original;
		
		if($since > 604800) {
			$print = $this->dateTimer('date', $original);
		
			if($since > 31536000) {
					$print = $this->dateTimer('long', $original);
					return $print;
				}
	
			return $print;
	
		}
		
		for ($i = 0, $j = count($chunks); $i < $j; $i++) {
			
			$seconds = $chunks[$i][0];
			$name = $chunks[$i][1];
			
			if (($count = floor($since / $seconds)) != 0) {
				break;
			}
		}
	
		$print = ($count == 1) ? '1 '.$name : "$count {$name}s";
	
		return $print." ago";
	
	}
											
	/*
	 * dateTimer: Convert a timestamp to a date output
	*/	
	public function dateTimer($type = '', $time = 0) {
	
		switch($type) {
			case 'date':
				$string = 'l jS F Y';
			break;
			case 'loan':
				$string = 'j F Y';
			break;
			case 'due':
				$string = 'd / m';
			break;
			default:
				$string = 'D m M Y H:i:s';
			break;
		}	
				
		if(!empty($time)) {
			return date($string, $time);
		} else {
			return date($string);
		}
		
	}							
	
	/*
	 * getDirectoryFiles: Recursive call to list and return all directory files
	 *
	 * @return $directoryList - array containing the files and folders
	*/	
	public function getDirectoryFiles($directory, $excludeIndex = true){
					
		# Create an array to hold directory list
		$results = array();
	
		# Create a handler for the directory
		if(!$handler = opendir($directory)) {
			return;
		}
	
		# Open directory
		while(false !== ($file = readdir($handler))) {
	
			# if file isn't this directory or its parent, add it to the results
			if(($file != "." && $file != "..") && (($excludeIndex && $file != 'index.php') || !$excludeIndex)) {
				$results[] = $file;
			}
	
		}
	
		# Tidy up: close the handler
		closedir($handler);
	
		# Done!
		return $results;
	
	}
																	
	/*
	 * cleanDirectory: Delete all files in a given directory
	*/	
	public function cleanDirectory($directory, $deleteSelf = false) {
		
		# Create a handler for the directory
		if(!$handler = opendir($directory)) {
			return;
		}
		
		# Open directory
		while(false !== ($file = readdir($handler))) {
			if($file == '.' || $file == '..') {
				continue;
			}
			if(!unlink($directory.'/'.$file)) {
				$this->cleanDirectory($directory.'/'.$file, true);
			}
		}
		
		# Remove own folder
		if($deleteSelf){
			closedir($dh);			
			rmdir($directory);
		}
		
	}
	
	/*
	 * redirect: Redirect to a given page
	 *
	 * @param $location - The page to redirect too
	*/
	public function redirect($page = ''){
				
		header("Location: ".$this->config['root_url'].'index.php?page='.$page);
		
	}
	
	private function getEncryptionKey($keySize) {
		
		# Get our keys
		$key1 = md5($this->cipherKeys[0]);
		$key2 = md5($this->cipherKeys[1]);
	
		# Create unique key
		$key = substr($key1, 0, $keySize/2) . substr(strtoupper($key2), (round(strlen($key2) / 2)), $keySize/2);	
		$key = substr($key.$key1.$key2.strtoupper($key1), 0, $keySize);
		
		# Return key		
		return $key;
	
	}
	
	private function quickEncrypt($clearText) {
		
		# Get keysize and key		
		if(empty($this->cipherKey)) {
						
			# Get the cipher key
			$this->cipherKey = $this->getEncryptionKey(32);
			
		}
		
		# Create our IV key:
		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		
		# Get our encrypted text
		$cipherText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->cipherKey, $clearText, MCRYPT_MODE_ECB, $iv);
		
		# Return our string
		return trim(base64_encode($cipherText));
		
	}
	
	private function quickDecrypt($value) {
		
		# Decode our string
		$cipherText = base64_decode($value);
				
		# Get keysize and key		
		if(empty($this->cipherKey)) {
						
			# Get the cipher key
			$this->cipherKey = $this->getEncryptionKey(32);
			
		}
		
		# Verify our IV size:
		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		
		# Decrypt the string
		$clearText = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->cipherKey, $cipherText, MCRYPT_MODE_ECB, $iv);		
		
		# Return the clearText
		return trim($clearText);
		
	}
	
	public function encryptData($clearText){
		
		# Create the cipher object:
		$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
		
		# Get keysize and key		
		if(empty($this->cipherKey)) {
			
			# Get the keysize
			$keySize = mcrypt_enc_get_key_size($cipher);
			
			# Get the cipher key
			$this->cipherKey = $this->getEncryptionKey($keySize);
			
		}
		
		// Here's some PHP code to verify our IV size:
		$iv_size = mcrypt_enc_get_iv_size($cipher);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		
		if(mcrypt_generic_init($cipher, $this->cipherKey, $iv) != -1) {
			
			# PHP pads with NULL bytes if $clearText is not a multiple of the block size..
			$cipherText = mcrypt_generic($cipher, $clearText);
			
			# Clean up our cipher
			mcrypt_generic_deinit($cipher);
			mcrypt_module_close($cipher);
			
		}		
				
		return trim(base64_encode($cipherText).'_'.$this->quickEncrypt($iv));
				
	}
	
	public function decryptData($data){	
	
		# Get our data
		$parts = explode("_", $data);
		
		# Decode our string
		$cipherText = base64_decode($parts[0]);
		
		# Get our IV key
        $iv = $this->quickDecrypt($parts[1]);         
		
		# Create cipher object
		$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
		
		# Get keysize and key		
		if(empty($this->cipherKey)) {
			
			# Get the keysize
			$keySize = mcrypt_enc_get_key_size($cipher);
			
			# Get the cipher key
			$this->cipherKey = $this->getEncryptionKey($keySize);
			
		}	
		
		if(mcrypt_generic_init($cipher, $this->cipherKey, $iv) != -1) {
			
			# Decrypt to our clear text string
			$clearText = mdecrypt_generic($cipher, $cipherText);
			
			# Clean up our cipher
			mcrypt_generic_deinit($cipher);
			mcrypt_module_close($cipher);
			
		}
				
		return trim($clearText);
			
	}				
						
}

?>